package com.yunpuvip.sachet.rest.controller.port;

import cn.hutool.core.util.IdUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;

import com.ijpay.alipay.AliPayApi;
import com.yunpuvip.sachet.biz.entity.Order;
import com.yunpuvip.sachet.biz.entity.Payment;
import com.yunpuvip.sachet.biz.service.*;
import com.yunpuvip.sachet.modular.constant.ApplicationConstant;
import com.yunpuvip.sachet.modular.constant.enumconstant.PayType;
import com.yunpuvip.sachet.modular.constant.enumconstant.PaymentType;
import com.yunpuvip.sachet.modular.constant.response.ServerResponse;
import com.yunpuvip.sachet.modular.core.exception.RestServiceExceptionEnum;
import com.yunpuvip.sachet.modular.vo.rest.request.UserPrepayVo;
import com.yunpuvip.sachet.rest.common.util.pay.AliPayTool;
import com.yunpuvip.sachet.rest.common.util.wxtool.WxPayTool;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.Map;

/**
 * @ auther wushaohong
 * @ date  2019/8/11
 **/
@RequestMapping("wxpay")
@RestController
@Slf4j
public class PayController  {

    @Autowired
    private SysparamService sysparamService;

    @Autowired
    OrderService orderService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    PlayerService playerService;

    @Autowired
    BalanceHistoryService balanceHistoryService;

    @Autowired
    private AliPayTool aliPayTool;

    /**
     * 用户预支付
     * @return
     */
    @RequestMapping("wxPrepay")
    public Object userRechangeToPreppay(@Valid UserPrepayVo userPrepayVo) {
        @NotEmpty(message = "用户openId不能为空") String openId = userPrepayVo.getOpenId();
        @NotNull(message = "支付账单ID不能为空") Integer paymentId = userPrepayVo.getPaymentId();

        //余额支付的金额
        BigDecimal subAmout = userPrepayVo.getSubAmout();
        Payment payment = paymentService.getById(paymentId);
        //先判断订单状态
        if (!paymentService.isPaymentOk(payment)) {
            //订单过期
            log.info("异常订单 id：{}", paymentId);
            return ServerResponse.creatByErrorEnum(RestServiceExceptionEnum.ORDER_ERROR);
        }
        Integer playerId = payment.getPlayerId();
        //获取缴费单类型
        String type = payment.getPayType();
        Integer paymentType = Integer.valueOf(type);
        String orderNo = payment.getOrderNo();
        BigDecimal totalFee = payment.getOrderPayPrice();
        Integer payMethod = userPrepayVo.getPayMethod();
        //BigDecimal totalFee = BigDecimal.valueOf(0.01);
        //判读用户是否为订单支付同时使用了余额支付且余额支付的金额大于0
        log.info("判断是否使用余额支付 subAmount：{}", subAmout);
        BigDecimal sub = subAmout.setScale(2, BigDecimal.ROUND_HALF_UP);
        totalFee = totalFee.setScale(2, BigDecimal.ROUND_HALF_UP);
        if (PayType.REST.getStatus().equals(payMethod)) {
            //余额支付
            if (PaymentType.ORDER.getStatus().equals(paymentType) && BigDecimal.ZERO.compareTo(subAmout) < 0 && totalFee.compareTo(sub) <= 0) {
                //扣减用户的余额，并生成记录
                Integer returenCode = balanceHistoryService.insertSubBanlanceHistoryAndSubPlayerBalance(subAmout, playerId,payment);
                //插入余额支付的信息到订单
                Order order = orderService.getOrderByorderNo(orderNo);
                BigDecimal shouldPay = totalFee;
                totalFee = totalFee.subtract(subAmout);
                order.setPayPrice(totalFee);
                order.setPayBalance(order.getPayPrice().add(subAmout));
                orderService.updateById(order);
                //判读余额是否已扣
                if (returenCode > 0) {
                    payment.setPayMethod(PayType.REST.getStatus());
                    log.info("使用余额支付成功 subAmount：{}------shouldPay：{}", sub, shouldPay);
                    //判断余额支付金额是否等于缴费单的金额,是的话直接返回，不会掉微信支付
                    if (shouldPay.compareTo(sub) == 0) {
                        log.info("使用余额全款支付成功 subAmount：{}", subAmout);
                        //修改订单状态
                        //此时微信不需支付
                        payment.setOrderPayPrice(BigDecimal.ZERO);
                        paymentService.NotifyTOUpadtePaymentAndAddBalanceRecord(payment);
                        return ServerResponse.creatBySuccess("订单已支付");
                    } else {
                        //没有全额支付，那么需要，重新设定价格
                        log.info("没有全额支付，那么需要，重新设定价格");
                        payment.setOrderPayPrice(totalFee);
                        paymentService.updateById(payment);
                    }
                }
            } else {
                log.info("使用余额支付失败 subAmount：{}", subAmout);
                return ServerResponse.creatByErrorEnum(RestServiceExceptionEnum.REST_CANT_DEDUCTION);
            }

        } else if (PayType.ALIPAY.getStatus().equals(payMethod)) {
            try {

                String o = aliPayTool.originPay(payment);
                return o;
            } catch (Exception e) {
                e.printStackTrace();
            }
            //  return "success";
            return ServerResponse.creatByErrorMsg("支付信息有误");
        }
        else if (PayType.WX_H5.getStatus().equals(payMethod)) {
            //配置支付信息
            WxPayConfig wxPayConfig = new WxPayConfig();
            wxPayConfig.setMchKey(sysparamService.getSysparamVlaue(ApplicationConstant.MCHKEY));
            wxPayConfig.setMchId(sysparamService.getSysparamVlaue(ApplicationConstant.MCHID));
            String host = sysparamService.getSysparamVlaue(ApplicationConstant.WEBHOST);
            String notify = sysparamService.getSysparamVlaue(ApplicationConstant.NOTIFYURL);
            String notifyUrl = host + notify;
            wxPayConfig.setNotifyUrl(notifyUrl);
            wxPayConfig.setAppId(sysparamService.getSysparamVlaue(ApplicationConstant.APPID));
            //wxPayConfig.setPayBaseUrl("https://api.mch.weixin.qq.com/pay/unifiedorder");
            wxPayConfig.setTradeType("JSAPI");
            WxPayService wxPayService = WxPayTool.setWxpayConfig(wxPayConfig);
            //请求微信拉起预支付
            try {
                WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
                String appId = wxPayConfig.getAppId();
                String mchId = wxPayConfig.getMchId();
                String tradeType = wxPayConfig.getTradeType();
                String mchKey = wxPayConfig.getMchKey();

                orderRequest.setAppid(appId);
                orderRequest.setMchId(mchId);
                orderRequest.setOpenid(openId);
                orderRequest.setNonceStr(IdUtil.createSnowflake(1, 1).nextId() + "");
                //内容加密类型
                orderRequest.setSignType("MD5");
                orderRequest.setBody(PaymentType.getPaymetnMsg(paymentType));
                orderRequest.setOutTradeNo(orderNo);
                orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(totalFee.toString()));//元转成分
                orderRequest.setSpbillCreateIp(InetAddress.getLocalHost().getHostAddress());
                orderRequest.setNotifyUrl(notifyUrl);
                orderRequest.setTradeType(tradeType);
                //拼接字符串
                String signStr =
                        "appid=" + orderRequest.getAppid() + "&" +
                                "body=" + orderRequest.getBody() + "&" +
                                "mch_id=" + orderRequest.getMchId() + "&" +
                                "nonce_str=" + orderRequest.getNonceStr() + "&" +
                                "notify_url=" + orderRequest.getNotifyUrl() + "&" +
                                "out_trade_no=" + orderRequest.getOutTradeNo() + "&" +
                                "sign_type=" + orderRequest.getSignType() + "&" +
                                "spbill_create_ip=" + orderRequest.getSpbillCreateIp() + "&" +
                                "total_fee=" + orderRequest.getTotalFee() + "&" +
                                "trade_type=" + orderRequest.getTradeType() + "&";
                signStr += "key=" + mchKey;
                System.out.println("加密前：" + signStr);
                signStr = DigestUtils.md5DigestAsHex(signStr.getBytes());
                String sign = signStr.toUpperCase();
                orderRequest.setSign(sign);
                Object order = wxPayService.createOrder(orderRequest);
                return ServerResponse.creatBySuccess(order);
            } catch (Exception e) {
                log.error("微信支付失败！订单号：{},原因:{}", orderNo, e.getMessage());
                e.printStackTrace();
                return ServerResponse.creatByErrorMsg("支付失败，请稍后重试！");

            }
        }
        return ServerResponse.creatByErrorMsg("支付信息有误");
    }
    @RequestMapping("aliPrepay")
    public void userRechangeToPreppay (@Valid UserPrepayVo userPrepayVo, HttpServletResponse httpResponse){
        @NotNull(message = "支付账单ID不能为空") Integer paymentId = userPrepayVo.getPaymentId();

        //余额支付的金额
        BigDecimal subAmout = userPrepayVo.getSubAmout();
        Payment payment = paymentService.getById(paymentId);
        //先判断订单状态
        if (!paymentService.isPaymentOk(payment)) {
            //订单过期
            log.info("异常订单 id：{}", paymentId);
            //return ServerResponse.creatByErrorEnum(RestServiceExceptionEnum.ORDER_ERROR);
        }
        Integer playerId = payment.getPlayerId();
        //获取缴费单类型
        try {
               /* AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
                alipayTradeWapPayModel.setOutTradeNo(orderNo);
                alipayTradeWapPayModel.setTotalAmount(totalFee.toString());
                String s = aliPayTool.aliPay(alipayTradeWapPayModel);*/
            String form = aliPayTool.originPay(payment);
            System.out.println(form);
            httpResponse.setContentType("text/html;charset=UTF-8");
            httpResponse.getWriter().write(form);//直接将完整的表单html输出到页面
            httpResponse.getWriter().flush();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 微信支付的回调
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("notify")
    public String payNotify (HttpServletRequest request, HttpServletResponse response){
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayService wxPayService = WxPayTool.getWxPayServiceInstance();
            WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
            String orderNo = result.getOutTradeNo();
            String tradeNo = result.getTransactionId();
            String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
            // 加入自己处理订单的业务逻辑，需要判断订单是否已经支付过，否则可能会重复调用
            //修改缴费单和订单状态状态,充值的话还要添加充值记录
            Payment payment = new Payment();
            payment.setOrderNo(orderNo);
            //处理订单，同时插入余额变更记录
            payment.setPayMethod(PayType.WX_H5.getStatus());
            boolean b = paymentService.NotifyTOUpadtePaymentAndAddBalanceRecord(payment);
            return b ? WxPayNotifyResponse.success("处理成功!") : WxPayNotifyResponse.fail("订单异常");
        } catch (Exception e) {
            log.error("微信回调结果异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }


    @RequestMapping("AliPayNotify")
    public String alipayNotify (HttpServletRequest request, HttpServletResponse response){
        try {
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            for (Map.Entry<String, String> entry : params.entrySet()) {
                System.out.println(entry.getKey() + " = " + entry.getValue());
            }
            String publicKey = sysparamService.getSysparamVlaue(ApplicationConstant.AlipaySysparam.AlipayCertPath);
            String sign = params.get("sign") ;
            System.err.println("publicKey:"+publicKey);
            boolean verify_result = AlipaySignature.rsaCertCheckV1(params, publicKey, "UTF-8",
                    "RSA2");

            System.err.println("verify_result:"+verify_result);
            if (verify_result) {
                // 验证成功
                // TODO 加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
                String out_trade_no = params.get("out_trade_no");
                String totalAmount = params.get("total_amount");
                Payment payment = paymentService.getPaymentByOrderNo(out_trade_no);
                payment.setPayMethod(PayType.ALIPAY.getStatus());
                paymentService.NotifyTOUpadtePaymentAndAddBalanceRecord(payment);
                System.out.println("notify_url 验证成功succcess");
                return "success";
            } else {
                System.out.println("notify_url 验证失败");
                // TODO
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }

    }

   /* @RequestMapping("aliPay")
    public Object alipay (HttpServletRequest request, HttpServletResponse response){
        try {
            AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
            alipayTradeWapPayModel.setOutTradeNo("12313");
            alipayTradeWapPayModel.setTotalAmount("0.01");
            String s = aliPayTool.originPay(alipayTradeWapPayModel);
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";
    }
*/
}
